/**********************************************************************
 * FILE : JMSWorker.java
 * CREATE DATE : 2011-11-23
 * DESCRIPTION :
 * CHANGE HISTORY LOG
 * ---------------------------------------------------------------------
 * NO.| DATE | NAME | REASON | DESCRIPTION
 * ---------------------------------------------------------------------
 * 1 | 2011-11-23 | Sting | 创建草稿版本
 * ---------------------------------------------------------------------
 */
package com.sgm.de.benchmark;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import static com.sgm.de.benchmark.Cmder.*;
/**
 * @author Sting
 *         <p>
 */
public class JMSAgent {

    String JAVAW = "java";
    private BKCode agentStatus = BKCode.Agent_Ready;
    private List<ProcessConfig> managedProcess = new ArrayList<ProcessConfig>();
    private int processSEQ = 0;
    private Console consoleListener;

    /**
     * @param lOCAL_SYNC_Q
     * @param lOCAL_ASYNC_Q
     * @param rEMOTE_SYNC_Q
     * @param rEMOTE_ASYNC_Q
     * @param poolSize
     */
    public JMSAgent() {
        consoleListener = new Console();
        Thread t = new Thread(consoleListener);
        t.start();
    }

    /**
     * 本地启动使用
     * @return
     * @throws IOException
     */
    public void startProcess(ProcessConfig config) throws IOException {
        ProcessBuilder build = new ProcessBuilder();
        List<String> command = new ArrayList<String>();
        command.add(JAVAW);
        command.add("-classpath");
        command.add(System.getProperty("java.class.path"));
        command.add("com.sgm.de.benchmark.JMSProcesser");
        build.command(command);
        build.redirectErrorStream(true);
        System.out.println(build.command());
        Process p = null;
        try {
            p = build.start();
            PrintWriter w = new PrintWriter(new OutputStreamWriter(p.getOutputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        final BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
        connProcessor(config);
        Thread t = new Thread(new Runnable() {
            public void run() {
              String line;
                try {
                    while ((line = br.readLine()) != null) {
                        System.out.println("[processor]" + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        
        // exec("config 127.0.0.1 127.0.0.1 10.203.27.134 7003  DEALER_CF TEST");
        exec("quantity 1000");
        exec("addThread 5");
        exec("msgsize 3");
        exec("runTest");
        exec("stop");
    }
    
    public void connProcessor(final ProcessConfig config) {
        Socket socket;
        try {
            socket = new Socket(config.getProcessorIp(), config.getProcessorPort());
            while (socket.isConnected()) {
                System.out.printf("connected at %s\n", config.getProcessorPort());
                PrintWriter req = new PrintWriter(socket.getOutputStream(), true);
                BufferedReader resp = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                Ob ob = new Ob(config, req);
                ob.directComand(config(config));
                consoleListener.addObserver(ob);
                break;
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public void exec(String cmd) {
        consoleListener.acceptCmd(cmd);
    }

    private class Ob implements Observer {

        private PrintWriter req;
        private ProcessConfig config;

        public Ob(ProcessConfig config, PrintWriter req) {
            this.config = config;
            this.req = req;

        }

        @Override
        public void update(Observable o, Object arg) {
            List<String> cmd = Arrays.asList(((String) arg).split(" "));
            Method[] declaredMethods = Cmder.class.getDeclaredMethods();
            for(Method m:declaredMethods){
                if(m.getName().equalsIgnoreCase(cmd.get(0))){
                    try {
                        List<String> args = cmd.subList(1, cmd.size());
                        // Class[] clazz = m.getParameterTypes();
                        // Object[] invokeArgs = new Object[clazz.length];
                        // for (int i = 0; i < clazz.length; i++) {
                        // Object obj = clazz[i].cast(args[i]);
                        // invokeArgs[i] = obj;
                        // }
                        String jsonComand = (String) m.invoke(null, args.toArray(new String[] {}));
                        req.println(jsonComand);
                    } catch (Exception e) {
                        System.err.print("command sytax error:\t");
                        System.out.println(e.getLocalizedMessage());
                    }
                }
            }
        }

        public void directComand(String cmd) {
            req.println(cmd);
        }
    }

    private class Console extends Observable implements Runnable {
        public void run() {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String cmd;
            try {
                while((cmd=br.readLine())!=null){
                    if(!cmd.equals("")){
                        acceptCmd(cmd);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void acceptCmd(String cmd) {
            setChanged();
            notifyObservers(cmd);
        }

    }
}
